home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / UTIL_SRC / C126.ZIP / LEX.ZIP / LEX.C < prev    next >
Text File  |  1990-01-19  |  15KB  |  539 lines

  1. /********************************************************************
  2.  * C Users Group (U.K) C Source Code Library File CUGLIB.015        *
  3.  * Inquiries to: M. Houston, 36 Whetstone Clo. Farquhar Rd.         *
  4.  * Edgbaston, Birmingham B15 2QN ENGLAND                *
  5.  ********************************************************************
  6.  * File name: lex.c
  7.  * Program name: lex
  8.  * Source of file: West Midlands OPUS BBS
  9.  * Purpose: An MS-DOS copy of the UNIX utility of the same name.
  10.  * Changes: <who what when & why major changes have been made>      
  11.  ********************************************************************/
  12.  
  13. /*  lex.c - main module, LEX system
  14.  *          -- initialisation, allocation, set creation
  15.  *
  16.  * Copyright (c) 1978 Charles H. Forsyth
  17.  *
  18.  * Revised for PDP-11 (Decus) C by Martin Minow
  19.  *
  20.  * Modified 02-Dec-80 Bob Denny -- Conditionalized debug code for smaller size
  21.  *                           01 -- Moved calls to dfa build, min, print, write
  22.  *                                  and to stat, and code for ending() into
  23.  *                                  this module so that 'ytab' could be put
  24.  *                                  into overlay region.
  25.  *          29-May-81 Bob Denny -- More extern hacking for RSX overlaying.
  26.  * More     19-Mar-82 Bob Denny -- New C library & compiler
  27.  * More     03-May-82 Bob Denny -- Final touches, remove unreferenced autos
  28.  *          28-Aug-82 Bob Denny -- Add "-s" switch to supress references to
  29.  *                                  "stdio.h" in generated code.  Add switch
  30.  *                                  comments in code. Add -e for "easy" com-
  31.  *                                  mand line. "lex -e file" is the short way
  32.  *                                  of saying:
  33.  *                                      "lex -i file.lxi -o file.c -t file"
  34.  * More(!)  30-Oct-82 Bob Denny -- Fix RSX ODL to put lots of FCS junk into
  35.  *                                  overlay, pick up (badly needed) 3KW for
  36.  *                                  NFA nodes, etc.  Change static allocations
  37.  *                                  in LEXLEX.H for RSX so can do non-trivial
  38.  *                                  things.  Task is now big on RSX and grows
  39.  *                                  from big to huge as it runs.
  40.  *                                 Fix "-s" support so it is again possible
  41.  *                                  to do a lexswitch() (dumb!).
  42.  *          14-Apr-83 Bob Denny    VAX-11 C workarounds.
  43.  *                                 Fix definition of toupper().
  44.  *        20-Nov-83 Scott Guthery  Adapt for IBM PC & DeSmet C
  45.  *          20-May-87 Jim Kyle     Adapt to MSC V4.0 for lint-free use
  46.  */
  47.  
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include "system.h"                     /* includes system configuration constants */
  52. #include "lh.h"
  53.  
  54. struct nfa nfa [ MAXNFA ];
  55. struct nfa * nfap =& nfa [ 1 ];
  56.  
  57. struct xset sets [ NCHARS ];
  58. char insets [ NCHARS ];
  59.  
  60. struct trans trans [ NTRANS ];
  61. struct trans * transp =& trans [ 0 ];
  62.  
  63. char ccls [ NCCLS ][( NCHARS + 1 ) / NBPC ];
  64. int nccls ;
  65.  
  66. int ndfa ;
  67. struct dfa dfa [ MAXDFA ];
  68. struct move move [ NNEXT ];
  69.  
  70. char * tabname = "lextab";
  71. char tabfile [ 15 ];
  72. char * infile = NULL;
  73. char * outfile = NULL;
  74.  
  75. #ifdef DEBUG
  76.   char * dumpfile = "lex.out";
  77.   int lldebug = 0;
  78. #endif
  79.  
  80. int llnxtmax = 0;
  81.  
  82. FILE * llout;
  83. FILE * lexin;
  84. FILE * lexlog;
  85.  
  86. /*
  87.  * Flags.  Allow globals only for those requiring same. Some only
  88.  * used for checking for bad combos.
  89.  */
  90. int aflag = 0;                          /* Ignore non-ASCII in [^ ...] */
  91. static int eflag = 0;                   /* Easy command line */
  92. static int iflag = 0;                   /* "-i" given */
  93. int mflag = 0;                          /* Enable state minimization (not imp.) */
  94. static int oflag = 0;                   /* "-o" given */
  95. int sflag = 0;                          /* Supress "#include <stdio.h>" in output */
  96. static int tflag = 0;                   /* "-t" given */
  97.  
  98. struct set * setlist = 0;
  99.  
  100. void main ( argc, argv )int argc ;
  101. char * argv [];
  102. { register char * cp,
  103.      * cp2;
  104. #ifdef DEBUG
  105.     int vflag ;
  106.     vflag = 0;
  107. #endif
  108.   for (; argc > 1 && * argv [ 1 ] == '-'; argv ++ , argc -- )
  109.     switch ( tolower ( argv [ 1 ][ 1 ]))
  110.       {
  111. #ifdef DEBUG
  112. /*
  113.          * Create "verification" file, describing the scanner.
  114.          */
  115.         case 'v' :                        /* -v => lex.out        */
  116.           vflag ++ ;                      /* -v x.out => x.out    */
  117.           if ( argc > 2 && argv [ 2 ][ 1 ] != '1' )
  118.             { -- argc;
  119.               dumpfile = ( ++ argv )[ 1 ];
  120.             }
  121.           break;
  122. /*
  123.          * Enable debug displays
  124.          */
  125.  
  126.         case 'd' :
  127.           lldebug ++ ;
  128.           break;
  129. #endif
  130. /*
  131.          * Enable state minimization. Currently not implemented.
  132.          */
  133.       case 'm' :
  134.         mflag ++ ;
  135.         break;
  136. /*
  137.          * Disable matching of non-ASCII characters (codes > 177(8))
  138.          * for exception character classes (form "[^ ...]").
  139.          */
  140.  
  141.       case 'a' :
  142.         aflag ++ ;
  143.         break;
  144. /*
  145.          * Supress "#include <stdio.h>" in generated
  146.          * code for programs not using standard I/O.
  147.          */
  148.  
  149.       case 's' :
  150.         sflag ++ ;
  151.         break;
  152. /*
  153.          * "Easy" command line
  154.          */
  155.  
  156.       case 'e' :
  157.         if ( iflag || oflag || tflag )
  158.           { error ( "Illegal switch combination\n" );
  159.             exit ( 1 );
  160.           }
  161.         if ( -- argc <= 1 )
  162.           { error ( "Missing name\n" );
  163.             exit ( 1 );
  164.           }
  165.         if ( strlen ( tabname = ( ++ argv )[ 1 ]) > 8 )
  166.           { error ( "Name too long\n" );
  167.             exit ( 1 );
  168.           }
  169.         infile = malloc ( 14 );
  170.         outfile = malloc ( 12 );
  171.         strcpy ( infile, tabname );
  172.         strcat ( infile, ".lxi" );
  173.         printf ( "Input read from %s\n", infile );
  174.         if (( lexin = fopen ( infile, "r" )) == NULL )
  175.           { error ( "Cannot open input \"%s\"\n", infile );
  176.             exit ( 1 );
  177.           }
  178.         strcpy ( outfile, tabname );
  179.         strcat ( outfile, ".c" );
  180.         break;
  181. /*
  182.          * Specify input file name.
  183.          */
  184.  
  185.       case 'i' :
  186.         if ( eflag )
  187.           { error ( "Illegal switch combination\n" );
  188.             exit ( 1 );
  189.           }
  190.         iflag ++ ;
  191.         if ( -- argc <= 1 )
  192.           { error ( "Missing input file\n" );
  193.             exit ( 1 );
  194.           }
  195.         infile = ( ++ argv )[ 1 ];
  196.         printf ( "Input read from %s\n", infile );
  197.         if (( lexin = fopen ( infile, "r" )) == NULL )
  198.           { error ( "Cannot open input \"%s\"\n", infile );
  199.             exit ( 1 );
  200.           }
  201.         break;
  202. /*
  203.          * Specify output file name. Default = "lextab.c"
  204.          */
  205.  
  206.       case 'o' :
  207.         if ( eflag )
  208.           { error ( "Illegal switch combination\n" );
  209.             exit ( 1 );
  210.           }
  211.         oflag ++ ;
  212.         if ( -- argc <= 1 )
  213.           { error ( "Missing output file" );
  214.             exit ( 1 );
  215.           }
  216.         outfile = ( ++ argv )[ 1 ];
  217.         break;
  218. /*
  219.          * Specify table name.  Default = "lextab.c".  If "-o"
  220.          * not given, output will go to "tabname.c".
  221.          */
  222.  
  223.       case 't' :
  224.         if ( eflag )
  225.           { error ( "Illegal switch combination\n" );
  226.             exit ( 1 );
  227.           }
  228.         tflag ++ ;
  229.         if ( -- argc <= 1 )
  230.           { error ( "Missing table name" );
  231.             exit ( 1 );
  232.           }
  233.         if ( strlen ( tabname = ( ++ argv )[ 1 ]) > 8 )
  234.           { error ( "Table name too long\n" );
  235.             exit ( 1 );
  236.           }
  237.         break;
  238.  
  239.       default :
  240.         error ( "Illegal option: %s\n", argv [ 1 ]);
  241.         exit ( 1 );
  242.       }
  243. #ifdef DEBUG
  244.     cp = ( vflag ) ? dumpfile : "NUL";
  245.     printf ( "Log written to %s\n", cp );
  246.     if (( lexlog = fopen ( cp, "w" )) == NULL )
  247.       { error ( "Cannot open \"%s\"", cp );
  248.         exit ( 1 );
  249.       }
  250. #endif
  251.   if ( infile == NULL )
  252.     { infile = malloc ( 31 );
  253.       strcpy ( infile, "lex.lxi" );
  254.     }
  255.   cp = infile;                          /* Fold infile to lower case */
  256. /*
  257.  * The following 2 loops cannot use the form "*cp++ = tolower(*cp)"
  258.  * due to a bug in VAX-11 C V1.0-09 where the pointer increment
  259.  * is done too soon (!).
  260.  */
  261.   while ( * cp )
  262.     { * cp = ( char ) tolower ( * cp );
  263.       cp ++ ;
  264.     }
  265.   cp = tabname;                         /* Fold tabname to lower case */
  266.   while ( * cp )
  267.     { * cp = ( char ) tolower ( * cp );
  268.       cp ++ ;
  269.     }
  270.   if ( outfile == NULL )
  271.     {                                   /*
  272.                  * Typical hacker's idiom!
  273.                  */
  274.       for ( cp = tabname, cp2 = tabfile; * cp2 =* cp ++ ; )
  275.         cp2 ++ ;
  276.       for ( cp = ".c"; * cp2 ++ =* cp ++ ; )
  277.         ;
  278.       outfile = tabfile;
  279.     }
  280.   printf ( "Analyzer written to %s\n", outfile );
  281.   if (( llout = fopen ( outfile, "w" )) == NULL )
  282.     { error ( "Can't create %s\n", outfile );
  283.       exit ( 1 );
  284.     }
  285.   heading ();
  286.   fprintf ( stderr, "Parse LEX source ...\n" );
  287.   if ( yyparse ())
  288.     error ( "Parse failed\n" );
  289.   fprintf ( stderr, "Build NFA then DFA ...\n" );
  290.   dfabuild ();                          /* 01+ */
  291.   fprintf ( stderr, "Minimize DFA ...\n" );
  292.   dfamin ();
  293.   fprintf ( stderr, "Create C source ...\n" );
  294.   dfaprint ();
  295.   dfawrite ();
  296. #ifdef DEBUG
  297.     stats ();
  298.     fclose ( lexlog );
  299. #endif                                                          /* 01- */
  300.   fprintf ( stderr, "\07LEX done.\n" );
  301.   fclose ( llout );
  302. }
  303. /* END OF MAIN */
  304.  
  305. /*
  306.  * This module was moved here from out.c so it could be called from
  307.  * ytab.c residing in same overlay region as out.c.
  308.  * 02-Dec-80  Bob Denny.
  309.  */
  310. /* 01+ */
  311. void ending ()
  312. { static int ended;
  313.   if ( ended ++ )
  314.     return;
  315.   fprintf ( llout, "\t}\n\treturn(LEXSKIP);\n}\n" );
  316.   setline ();
  317. }
  318.  
  319. #ifdef DEBUG
  320.   void stats ()
  321.   { fprintf ( lexlog, "\n" );
  322.     fprintf ( lexlog, "%d/%d NFA states, %d/%d DFA states\n", nfap - nfa, MAXNFA, ndfa, MAXDFA );
  323.     fprintf ( lexlog, "%d/%d entries in move vectors\n", llnxtmax, NNEXT );
  324.   }
  325.  
  326. /*
  327.  * Print a state set on { ... } form on lexlog.
  328.  */
  329.   void pset ( t, nf )register struct set * t;
  330.   { register int i;
  331.     fprintf ( lexlog, "{" );
  332.     for ( i = 0; i < t -> s_len; i ++ )
  333.       if ( nf )
  334.         fprintf ( lexlog, " %d", t -> s_els [ i ] - nfa );
  335.     else
  336.       fprintf ( lexlog, " %d", t -> s_els [ i ]);
  337.     fprintf ( lexlog, "}" );
  338.   }
  339.  
  340. /*
  341.  * Print a character to lexlog in readable form.
  342.  * Returns the number of characters generated.
  343.  */
  344.   chprint ( ch )
  345.   { register char * s;
  346.     ch &= 0377;
  347.     switch ( ch )
  348.       {
  349.       case '\t' :
  350.         s = "\\t";
  351.         break;
  352.  
  353.       case '\n' :
  354.         s = "\\n";
  355.         break;
  356.  
  357.       case '\b' :
  358.         s = "\\b";
  359.         break;
  360.  
  361.       case '\r' :
  362.         s = "\\r";
  363.         break;
  364.  
  365.       default :
  366.         if ( ch < 040 || ch >= 0177 )
  367.           { fprintf ( lexlog, "\\%03o", ch );
  368.             return ( 4 );
  369.           }
  370.         else
  371.           {
  372.             putc ( ( char ) ch, lexlog );
  373.             return ( 1 );
  374.           }
  375.       }
  376.     fprintf ( lexlog, s );
  377.     return ( 2 );
  378.   }
  379. #endif
  380.  
  381. /*
  382.  * The following functions simply
  383.  * allocate various kinds of
  384.  * structures.
  385.  */
  386. struct nfa *newnfa ( ch, nf1, nf2 )struct nfa * nf1, * nf2;
  387. { register struct nfa * nf;
  388.   if (( nf = nfap ++ ) >=& nfa [ MAXNFA ])
  389.     { error ( "Too many NFA states" );
  390.       exit ( 1 );
  391.     }
  392.   nf -> n_char = ch;
  393.   nf -> n_succ [ 0 ] = nf1;
  394.   nf -> n_succ [ 1 ] = nf2;
  395.   nf -> n_trans = 0;
  396.   nf -> n_flag = 0;
  397.   nf -> n_look = 0;
  398.   return ( nf );
  399. }
  400.  
  401. struct dfa *newdfa ()
  402. { register struct dfa * df;
  403.   if (( df =& dfa [ ndfa ++ ]) >=& dfa [ MAXDFA ])
  404.     { error ( "Out of dfa states" );
  405.       exit ( 1 );
  406.     }
  407.   return ( df );
  408. }
  409.  
  410. char *newccl ( ccl )char * ccl;
  411. { register char * p,
  412.      * q;
  413.   register int i;
  414.   int j ;
  415.   for ( j = 0; j < nccls; j ++ )
  416.     { p = ccl;
  417.       q = ccls [ j ];
  418.       for ( i = sizeof ( ccls [ j ]); i -- ; )
  419.         if ( * p ++ !=* q ++ )
  420.           goto cont ;
  421.       return ( ccls [ j ]);
  422.       cont :;
  423.     }
  424.   if ( nccls >= NCCLS )
  425.     { error ( "Too many character classes" );
  426.       exit ( 1 );
  427.     }
  428.   p = ccl;
  429.   q = ccls [ j = nccls ++ ];
  430.   for ( i = sizeof ( ccls [ j ]); i -- ; )
  431.     * q ++ =* p ++ ;
  432.   return ( ccls [ j ]);
  433. }
  434.  
  435. struct trans *newtrans ( st, en )struct nfa * st, * en;
  436. { register struct trans * tp;
  437.   if (( tp = transp ++ ) >=& trans [ NTRANS ])
  438.     { error ( "Too many translations" );
  439.       exit ( 1 );
  440.     }
  441.   tp -> t_start = st;
  442.   tp -> t_final = en;
  443.   en -> n_trans = tp;
  444.   return ( tp );
  445. }
  446.  
  447. /*
  448.  * Create a new set. `sf', if set, indicates that the elements of the
  449.  * set are states of an NFA). If `sf' is not set, the elements are state
  450.  * numbers of a DFA.
  451.  */
  452. struct set *newset ( v, i, sf )register struct nfa ** v;
  453. register int i;
  454. { register struct set * t;
  455.   register int k;
  456.   int setcomp ();
  457.   qsort ( ( char * ) v, i, sizeof ( * v ), setcomp );
  458.   for ( t = setlist; t; t = t -> s_next )
  459.     if ( t -> s_len == i && eqvec ( ( int * ) t -> s_els, ( int * ) v, i ))
  460.       return ( t );
  461.   t = ( struct set * ) lalloc ( 1,
  462.                           sizeof ( * t ) + i * sizeof ( t -> s_els [ 0 ]),
  463.                           "set nodes" );
  464.   t -> s_next = setlist;
  465.   setlist = t;
  466.   t -> s_final = 0;
  467.   t -> s_state = 0;
  468.   t -> s_flag = 0;
  469.   t -> s_len = i;
  470.   t -> s_group = 0;
  471.   t -> s_look = 0;
  472.   for ( v += i; i; )
  473.     { -- v;
  474.       if ( sf )
  475.         { if (( * v ) -> n_char == FIN )
  476.             t -> s_final = ( * v ) - nfa;
  477.           if (( * v ) -> n_flag & LOOK )
  478.             t -> s_look |= 1 << ( * v ) -> n_look;
  479.         }
  480.       else
  481.         {
  482.           k = ( int ) * v;
  483.           dfa [ k ]. df_name -> s_group = t;
  484.         }
  485.       t -> s_els [ -- i ] =* v;
  486.     }
  487.   return ( t );
  488. }
  489.  
  490. setcomp ( n1p, n2p )struct nfa ** n1p, ** n2p;
  491. { register struct nfa * n1, * n2;
  492.   n1 =* n1p;
  493.   n2 =* n2p;
  494.   if ( n1 > n2 )
  495.     return ( 1 );
  496.   if ( n1 == n2 )
  497.     return ( 0 );
  498.   return ( - 1 );
  499. }
  500.  
  501. eqvec ( a, b, i )register int * a,
  502.      * b,
  503.      i;
  504. { if ( i )
  505.     do
  506.       {
  507.         if ( * a ++ !=* b ++ )
  508.           return ( 0 );
  509.       }
  510.   while ( -- i )
  511.     ;
  512.   return ( 1 );
  513. }
  514.  
  515. /*
  516.  * Ask for core, and complain if there is no more.
  517.  */
  518. char *lalloc ( n,
  519.      s,
  520.      w )char * w;
  521. { register char * cp;
  522.   if (( cp = calloc ( n, s )) == NULL )
  523.     { fprintf ( stderr, "No space for %s", w );
  524. #ifdef DEBUG
  525.         if ( lldebug )
  526.           dfaprint ();
  527. #endif
  528.       exit ( 1 );
  529.     }
  530.   return ( cp );
  531. }
  532.  
  533. void error ( format, argument )char * format,
  534.      * argument;
  535. { fprintf ( stderr, format, argument );
  536. }
  537.  
  538. /* end of lex.c */
  539.